/********************************************
 * 功能说明: Organization实体与DTO之间接口数据转换实现
 * 模块名称:
 * 系统名称:
 * 软件版权: Frank
 * 系统版本: 1.0.0.1
 * 开发人员:
 * 开发时间: 2019-12-18 18:41:08
 * 审核人员:
 * 相关文档:
 * 修改记录: 修改日期 修改人员 修改说明
 *********************************************/
package com.spring.arch.uaa.web.converter;

import com.spring.arch.common.converter.AbstractConverter;
import com.spring.arch.common.exception.ExceptionHolder;
import com.spring.arch.common.idgenerator.IdGenerator;
import com.spring.arch.uaa.enums.OrganizationType;
import com.spring.arch.uaa.errorcode.UaaErrorCode;
import com.spring.arch.uaa.web.dto.WebOrganizationDTO;
import com.spring.arch.uaa.web.dto.WebOrganizationTreeDTO;
import com.spring.arch.common.converter.AbstractConverter;
import com.spring.arch.common.exception.ExceptionHolder;
import com.spring.arch.common.idgenerator.IdGenerator;
import com.spring.arch.uaa.enums.OrganizationType;
import com.spring.arch.uaa.errorcode.UaaErrorCode;
import com.spring.arch.uaa.model.Organization;
import com.spring.arch.uaa.repository.OrganizationRepository;
import com.spring.arch.uaa.web.dto.WebOrganizationDTO;
import com.spring.arch.uaa.web.dto.WebOrganizationTreeDTO;
import lombok.NonNull;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.persistence.EntityManager;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * Organization实体与DTO之间接口数据转换实现
 *
 * @author
 * @version 1.0.0.1
 * @since 2019-12-18 18:41:08
 */
@Component
public class WebOrganizationConverter extends AbstractConverter<Organization, WebOrganizationDTO> {

    @Autowired
    private OrganizationRepository organizationRepository;

    @Autowired
    private EntityManager entityManager;

    @Override
    public Organization toModel(@NonNull final WebOrganizationDTO dto) {
        if(dto.isNew()) {
            return constructModel(dto);
        } else {
            return updateModel(dto);
        }
    }

    @Override
    public WebOrganizationDTO toDTO(Organization model) {
        WebOrganizationDTO dto = new WebOrganizationDTO();
        dto.setParentId(model.getParent() == null ? null : model.getParent().getId());
        dto.setCode(model.getCode());
        dto.setName(model.getName());
        dto.setType(model.getType());

        this.convertCommonToDTO(model, dto);

        return dto;
    }

    public WebOrganizationTreeDTO toTreeDTO(Organization organization) {

        WebOrganizationTreeDTO dto = new WebOrganizationTreeDTO();

        dto.setId(organization.getId());
        dto.setName(organization.getName());
        dto.setChildren(toTree(organization));

        return dto;
    }

    private List<WebOrganizationTreeDTO> toTree(Organization organization) {

        List<WebOrganizationTreeDTO> childrenDto = new ArrayList<>();

        List<Organization> list =
                organizationRepository.findAllByParentIdAndDisableFalseOrderByCreatedDate(organization.getId());

        if(CollectionUtils.isEmpty(list)) {
            return null;
        }

        list.forEach(l -> {

            WebOrganizationTreeDTO dto = new WebOrganizationTreeDTO();
            dto.setId(l.getId());
            dto.setName(l.getName());
            dto.setChildren(toTree(l));

            childrenDto.add(dto);
        });

        return childrenDto;
    }


    /**
     * 构建新Model
     */
    private Organization constructModel(final WebOrganizationDTO dto) {
        final Organization model = new Organization();
        this.dtoToModel(dto, model);
        return model;
    }

    /**
     * 更新Model
     */
    private Organization updateModel(final WebOrganizationDTO dto) {
        final Organization model = this.organizationRepository.findById(dto.getId())
                .orElseThrow(() -> ExceptionHolder.serviceException(UaaErrorCode.E2001003001,
                        dto.getId().toString()));

        entityManager.unwrap(Session.class).evict(model);
        this.dtoToModel(dto, model);
        return model;
    }

    private void dtoToModel(final WebOrganizationDTO dto, final Organization model) {

        model.setParent(organizationRepository.findById(dto.getParentId()).orElseThrow(() ->
                ExceptionHolder.serviceException(UaaErrorCode.E2001003001, dto.getParentId().toString())));

        model.setTenant(model.getParent().getTenant());
        model.setProject(model.getParent().getProject());

        model.setCode(IdGenerator.uniqueCode());
        model.setName(dto.getName());
        model.setType(dto.getType());
    }

    public WebOrganizationTreeDTO toTreeGroupDTO(Organization organization) {

        WebOrganizationTreeDTO dto = new WebOrganizationTreeDTO();

        dto.setId(organization.getId());
        dto.setName(organization.getName());
        dto.setChildren(toTreeGroup(organization));

        return dto;
    }

    private List<WebOrganizationTreeDTO> toTreeGroup(Organization organization) {

        List<WebOrganizationTreeDTO> childrenDto = new ArrayList<>();

        List<Organization> list = organizationRepository.findAllByParentIdAndTypeNotAndDisableFalseOrderByCreatedDate(
                organization.getId(), OrganizationType.PROJECT);

        if(CollectionUtils.isEmpty(list)) {
            return null;
        }

        list.forEach(l -> {

            WebOrganizationTreeDTO dto = new WebOrganizationTreeDTO();
            dto.setId(l.getId());
            dto.setName(l.getName());
            dto.setChildren(toTree(l));

            childrenDto.add(dto);
        });

        return childrenDto;
    }

}
